Design - Command Service

Friday, March 24, 2023

9:47 AM

OneNote doesn't share Word's ability to embed UI controls on a page. Sadly, this means that there is no way to create an interactive form or embed any UI controls that can affect page content or invoke actions or commands. But, there's a trick employed by OneMore to create the illusion of interactivity by embedding smart hyperlinks on a page that can indirectly invoke OneMore commands. For example, OneMore emits hyperlinks that let you refresh a table of contents, footnote references, or update a PlantUML drawing when you edit the associated UML, just like the one at the bottom of this page that updates the diagram here.

 

Trusted Protocol Activation (Extract)

 

 

The Trusted Protocol Scheme

This is done by registering a trusted protocol as an indirection to initiate a Windows shell handler.

 

In fact, you use shell handlers every day! When you double-click a file with a known file type, Windows opens a program associated with that file type. How does that happen? There is an entry in the Windows Registry for each known file type that specifies a program to handle shell commands such as open and print. OneMore leverages this to associate a handler for a custom URI protocol ("http" and "https" are URI protocols)

 

Trusted Protocol Registration

Registering a custom scheme protocol handler is demonstrated below, as explained in this article.

 

The first entry declares the protocol. This key declares the "onemore" application; this key name is referenced below when creating the policy for the trusted protocol. The default value must begin with "URL:" and specifies a friendly name for the protocol scheme. The URL Protocol property is required and must be set to an empty string.

 

[HKEY_CLASSES_ROOT\onemore]

@="URL:OneMore Protocol Handler"

"URL Protocol"=""

 

This next section declares the application handler for the onemore: protocol scheme. In this case, the OneMoreProtocolHandler.exe application is specified along with standard CMD input parameters placeholders.

 

[HKEY_CLASSES_ROOT\onemore\shell]

[HKEY_CLASSES_ROOT\onemore\shell\open]

[HKEY_CLASSES_ROOT\onemore\shell\open\command]

@="\"C:\\Program Files\\River\\OneMoreAddIn\\OneMoreProtocolHandler.exe\" %1 %2 %3 %4 %5"

 

Finally, we have to create a policy that tells Windows to trust the protocol scheme. Noticed that this is per-user. The key must end with the protocol name, including the colon character as demonstrated here.

 

[HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Office\16.0\Common\Security\Trusted Protocols\All Applications\onemore:]

 

OneMore Protocol Handler

Now we can embed URLs on a page similar to

 

onemore://PlantUmlCommand/object-id

 

Look at the Extract URL below the image at the top of this page. It's the same as the Refresh URL but with an additonal "extract" parameter. When this link is clicked, OneNote passes this to Windows, which looks up the onemore: schema in the Registry and determines its default handler, in this case, the OneMoreProtocolHandler.exe application. The entire URL is passed as the first parameter into this application.

 

The handler application is simple in concept: it sends a message to a service listening from within the OneMore COM Surrogate process. The transport mechanism is a named pipe. The name of this pipe is derived from the default value on the registered protocol, in this case "URI:OneMore Protocol Handler".

 

The named pipe is constructed such that only the logged in user can send messages, as explained below.

 

Command Service

In our OnStartupComplete handler, OneMore starts a number of services, one of which is implemented by the CommandService class. This class spins up a worker thread that listens on the secured named pipe.

 

When a message is received, the incoming URI is parsed to extract the command name and any necessary parameters. Using the example above, the command name is "PlantUmlCommand" and the parameter is a unique object ID,

 

Examining the code, you'll notice that the constructor of the CommandService class accepts a reference to the command factory:

 

public CommandService(CommandFactory factory)

 

The factory invokes the named command, passing in the provided parameters.

 

Command args

All commands must implement the abstract Execute method declared in the base Command class. This method accepts an optional array of arguments. Normally, this list would be empty. However, commands that are indirectly re-entrant via the command service must interrogate the args parameter and decide what to do next. For example, the PlantUmlCommand will redraw the image specified by the object ID parameter.

 

 

──────────────────────────────────────────────────────────────────────────────────────────────────

Trusted Protocol Activation PlantUML (Refresh)

@startuml Trusted Protocol Activation

allowmixing

skin rose

skinparam defaultFontSize 9

rectangle #line:gray;line.dotted {

  file "URL Click" as URL

  component Handler

}

package "COM Surrogate" {

  component Service

  hexagon Command

}

json "Windows Registry" as Registry {

   "scheme":"onemore:",

   "handler":"OneMoreProtocolHandler.exe",

   "trust":"enabled"

}

URL -right-> Handler

Handler -right-> Service: "<< named pipe >>"

Registry -up-> Handler

Registry -up-> Service

Service -right-> Command

@enduml

 

 

#omwiki #omdeveloper #omdesign

 

© 2020 Steven M Cohn. All rights reserved.

Please consider a sponsorship or one-time donation to support ongoing development

 

Created with OneNote.